home *** CD-ROM | disk | FTP | other *** search
/ Packard Bell - Internet on a CD / internet on a cd.cdr / Internet / sites / Clementine_NASA / writegif.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-07-16  |  28.9 KB  |  959 lines

  1.  
  2.  
  3. /*  
  4. **************************************************************************
  5. *
  6. *        -----------------    
  7. *        |   WriteGIF    |
  8. *        -----------------        
  9. *
  10. *_TITLE WriteGIF writes a CompuServe GIF image when passed image data and size.
  11. *
  12. *_DESC  WriteGIF writes a CompuServe GIF image when a GIF file pointer, 
  13. *         an image buffer containing raw image data, number of lines,
  14. *         and sample per line is passed to the function writegif.
  15. *         The image buffer is assumed to contain a 256 gray scaled
  16. *         image with one byte of data representing one sample.
  17. *
  18. *         The GIF file written uses 87A GIF specs set up by
  19. *         CompuServe.  Under those specs its writes a GIF header,
  20. *         a logical screen descriptor, a global color table, an
  21. *         image descriptor, and the compressed image data.  It
  22. *         is highly recommended that anyone attempting to decipher
  23. *         this code should read the CompuServe specs on GIF files
  24. *         since many of the terms and names are taken from those
  25. *         specs (a familiarity with LZW compression might also be
  26. *         useful).
  27. *
  28. *         This piece of software was origionally developed on a Sun
  29. *         Sparc machine.  This version was made in order to deal
  30. *         with PC memory limitations.  This is a MS-DOS only version.
  31. *
  32. *         "The Graphics Interchange Format(c) is the Copyright property
  33. *         of CompuServe Incorporated.  GIF(sm) is a Service Mark
  34. *         property of CompuServe Incorporated."
  35. *    
  36. *_HIST  MAY 31 1994  David Larsen, USGS, Flagstaff Original Version
  37. *
  38. ***************************************************************************
  39. */
  40.  
  41. #include <stdio.h>
  42. #include <alloc.h>
  43. #include <stdlib.h>
  44.  
  45. #include "pds.h"
  46.  
  47. /*
  48. ******************************************************************************
  49. **
  50. **    Defined Macros
  51. **
  52. ******************************************************************************
  53. */
  54.  
  55.  
  56. /*misc macros*/
  57. #define LO_BYTE_16BIT                  (GIFdata & 255)
  58. #define HI_BYTE_16BIT                  ((GIFdata & 65280)/256)
  59. #define HEADER                    "GIF87a"
  60.  
  61. /*Error Codes*/
  62. #define ERROR                    -1    
  63. #define NO_ERROR                 0    
  64.  
  65. /*GIF image macros*/
  66. #define GIF_TRAILER                59    
  67. #define LOGICAL_SCREEN_PACKED_BIT_FIELDS    247
  68. #define BACKGROUND_COLOR_INDEX            0
  69. #define PIXEL_ASPECT_RATIO            0
  70. #define IMAGE_SEPARATOR                    44    
  71. #define IMAGE_LEFT_POSITION            0
  72. #define IMAGE_TOP_POSITION            0
  73. #define IMAGE_DESCRIPTOR_PACKED_BIT_FIELDS    0
  74. #define BLOCK_TERMINATOR            0
  75. #define TABLE_SIZE                    12007/*4099 12007 20011 40007 50021 */
  76. #define FIRST_NEW_OUTPUT_CODE                258
  77. #define BUFFER_SIZE                251
  78. #define MIN_CODE_SIZE                8
  79. #define START_CODE_BIT_SIZE            9
  80. #define CLEAR_CODE                    256    
  81. #define MAX_STRING_CODE                4096
  82. #define OVERFLOW                4096
  83. #define LZW_TERMINATOR_CODE            257
  84.  
  85. /*set up macros for a BOOLEAN type*/
  86. #define BOOLEAN                    char
  87. #define TRUE                    1
  88. #define FALSE                    0
  89.  
  90. /* Macro functions used in debugging */
  91. #define xx                     printf("xx\n")
  92. #define yy                     printf("yy\n")
  93. #define zz                     printf("zz\n")
  94.  
  95.  
  96.  
  97. /*
  98. ******************************************************************************
  99. **
  100. **    Type Definitions
  101. **
  102. ******************************************************************************
  103. */
  104.  
  105. /*a type definition for a string table entry in the
  106.   string table array (which is called HashTable in
  107.   this program)*/
  108. struct StrTabNode{    int        StringSize;  /*size of the string in
  109.                                  table*/
  110.             int        StringCode;  /*the code given to the
  111.                                string in table*/
  112.          };
  113. typedef struct StrTabNode StringTabNode; /*gives an easy name to
  114.                        struct StrTabNode*/
  115.  
  116.  
  117.  
  118. /*
  119. **************************************************************************
  120. **
  121. **    Prototypes
  122. **
  123. **************************************************************************
  124. */    
  125.  
  126.  /*Function that makes the GIF file. 
  127.     It returns an error code*/
  128. int         writegif(FILE *, long, long, CHARH *);
  129.  
  130.  /*Function that writes a header "GIF87A" to GIF file.
  131.    It returns an error code*/
  132. int         WriteHeader(FILE *);
  133.  
  134.  /*Function that writes the Logical Screen Descriptor to GIF file.
  135.     It returns an error code*/
  136. int         WriteLogicalScreenDescriptor(FILE *, long, long);
  137.  
  138.  /*Function that writes the Global Color Table to GIF file.
  139.    It returns an error code*/
  140. int         WriteGlobalColorTable(FILE *);
  141.  
  142.  /*Function that writes the image data to GIF file.
  143.    It returns an error code*/
  144. int         WriteImage(FILE *, CHARH * , long , long );
  145.  
  146.  /*Function that writes the Image Descriptor to GIF file.
  147.    It returns an error code*/
  148. int         WriteImageDescriptor(FILE *, long, long);
  149.  
  150.  /*Function that compresses the image and writes it to GIF file.
  151.    It returns an error code*/
  152. int        WriteImageDataBlock(FILE *, CHARH *,long, long);
  153.  
  154.  /*Function that compares two LZW strings.  It returns TRUE if they are
  155.    the same and FALSE if they are not*/
  156. BOOLEAN     CompareString(CHARH *, int, CHARH *, int );
  157.  
  158.  /*procedure that puts a string and its string code into the hash
  159.    table*/
  160. void         PutInTable(CHARH *, int, int, StringTabNode *,CHARH **);
  161.  
  162.  /*procedure that initializes the hash table to nothing*/
  163. void         InitTable(StringTabNode *);
  164.  
  165.  /*function that puts bytes into the GIF buffer.  If it fills up it
  166.    writes the buffer to the GIF file. It returns an error code*/
  167. int         PutInGIFBuffer(FILE *,  unsigned char *, unsigned char, int *);
  168.  
  169.  /*function that finds a string in the hash table.  It returns its
  170.    string code if it is in the table and NULL if not*/
  171. int         FindInTable(CHARH *, int, StringTabNode *, CHARH **);
  172.  
  173.  /*function that packs string codes and puts them into the GIF buffer.
  174.    It returns an error code*/
  175. int         WriteToGIF(FILE *,unsigned char *,int,char *,int *,int,int *);
  176.  
  177.  /*function that writes 8 bit sized data to the open GIF file
  178.    It returns an error code*/
  179. int         WriteGIFdata8(FILE *, unsigned char);
  180.  
  181.  /*function that writes 16 bit sized data to the open GIF file as lo
  182.    byte and hi byte It returns an error code*/
  183. int         WriteGIFdata16(FILE *, unsigned int);
  184.  
  185.  
  186.  
  187. /*
  188. *************************************************************************
  189. **
  190. **    This function calls all other functions in this file to
  191. **    create the GIF file.  This function outputs error messages if
  192. **    a problem occures during the creation of the GIF.  It returns
  193. **    ERROR if there was a problem and NO_ERROR if the GIF was created
  194. **    ok.
  195. **
  196. *************************************************************************
  197. */
  198. int writegif(    FILE *        GIFfile,    /*pointer to GIF file*/
  199.         long        Lines,      /*number of lines in image*/
  200.         long        Samples,    /*number of samples per line*/
  201.         CHARH *        ImageBuffer /*pointer to the ImageBuffer
  202.                           containing the raw image*/
  203.         )
  204. {
  205.    printf("Writing GIF file.\n");
  206.    /*Write the Header block. Print an error message and return the appropriate
  207.       error code if there was an error*/
  208.    if(WriteHeader(GIFfile)){
  209.       printf("**>ERROR writing the GIF file(1).\n");
  210.       return ERROR;
  211.    } /*end if*/
  212.  
  213.    /*Write the Logical Screen Descriptor block Print an error message and
  214.      return the appropriate error code if there was an error*/
  215.    if(WriteLogicalScreenDescriptor(GIFfile, Lines, Samples)){
  216.       printf("**>ERROR writing the GIF file(2).\n");
  217.       return ERROR;
  218.    } /*end if*/
  219.  
  220.    /*Write the Global Color Table block.  Print an error meaasage and
  221.      return the appropriate error code if there was an error*/
  222.    if(WriteGlobalColorTable(GIFfile)){
  223.       printf("**>ERROR writing the GIF file(3).\n");
  224.       return ERROR;
  225.    } /*end if*/
  226.  
  227.    /*Write the Image Descriptor block, compress the image,  and write the
  228.      compressed image data.  Print an error message and return the appropriate
  229.      error code if there was an error*/
  230.    if(WriteImage(GIFfile, ImageBuffer, Lines, Samples)){
  231.       printf("**>ERROR writing the GIF file(4).\n");
  232.       return ERROR;
  233.    } /*end if*/
  234.  
  235.    /*Write the Trailer to indicate the end of the image.  Print an error
  236.      message return the appropriate error code if there was an error*/
  237.    if(WriteGIFdata8(GIFfile, GIF_TRAILER)) {
  238.       printf("**>ERROR writing the GIF file(5).\n");
  239.       return ERROR;
  240.    } /*end if*/
  241.  
  242.  
  243.    /*if no errors occured during GIF creation then print a message and return
  244.      the appropriate error code */
  245.    printf("GIF file was successfully written.\n");
  246.    return NO_ERROR;
  247. }
  248.  
  249.  
  250.  
  251.  
  252. /*
  253. **************************************************************************
  254. **
  255. **     This function writes the header portion of the GIF file.  If an
  256. **    error occured it returns ERROR otherwise NO_ERROR.
  257. **
  258. **************************************************************************
  259. */
  260. int WriteHeader(FILE * GIFfile  /*pointer to the GIF file*/)
  261. {
  262.    char HeaderString[7] = HEADER;
  263.    int i;
  264.  
  265.    /*write header data.
  266.  
  267.      NOTE: the sizeof operator only indicates 6 characters of the string to 
  268.        write because it leaves off the string terminator
  269.    */
  270.    /*Write the Trailer to indicate the end of the image.  Print an error
  271.      message return the appropriate error code if there was an error*/
  272.    for(i = 0; i < 6; i++)
  273.       if(WriteGIFdata8(GIFfile, HeaderString[i]))
  274.      return ERROR;
  275.  
  276.    return NO_ERROR;
  277.  
  278. }
  279.  
  280.  
  281.  
  282. /*
  283. **************************************************************************
  284. **
  285. **     This function writes the logical screen descriptor portion of the
  286. **    GIF file.  If an error occured it returns ERROR otherwise NO_ERROR.
  287. **
  288. **************************************************************************
  289. */
  290. int WriteLogicalScreenDescriptor(    FILE * GIFfile, /*pointer to GIF file*/
  291.                     long     Lines,  /*number of lines
  292.                               in image*/
  293.                     long     Samples /*number of samples
  294.                               per line*/
  295.                 )
  296. {
  297.    /*write the width of the display device in pixels and return the
  298.      appropriate error code if there is an error*/
  299.    if(WriteGIFdata16(GIFfile, Samples))
  300.       return ERROR;
  301.  
  302.    /*write the height of the display device in pixels and return the
  303.      appropriate error code if there is an error*/
  304.    if(WriteGIFdata16(GIFfile, Lines))
  305.       return ERROR;
  306.  
  307.  
  308.    /*write the packed bit fields for:
  309.  
  310.      Global Color Table Flag     (bit  7  ),
  311.      Color Resolution        (bits 6-4),
  312.      Sort Flag             (bit  3  ), and
  313.      Size of Global Color Table (bits 2-0).
  314.  
  315.      Return the appropriate error code if there is an error
  316.    */
  317.    if(WriteGIFdata8(GIFfile, LOGICAL_SCREEN_PACKED_BIT_FIELDS))
  318.       return ERROR;
  319.  
  320.    /*write the background color index and return the
  321.      appropriate error code if there is an error*/
  322.    if(WriteGIFdata8(GIFfile, BACKGROUND_COLOR_INDEX))
  323.       return ERROR;
  324.  
  325.    /*write the pixel aspect ratio and return the
  326.      appropriate error code if there is an error*/
  327.    if(WriteGIFdata8(GIFfile, PIXEL_ASPECT_RATIO))
  328.       return ERROR;
  329.  
  330.    /*return the error code for no error if everything ran ok*/
  331.    return NO_ERROR;
  332. }
  333.  
  334.  
  335.  
  336. /*
  337. **************************************************************************
  338. **
  339. **     This function writes the global color table portion of the
  340. **    GIF file.  If an error occured it returns ERROR otherwise NO_ERROR.
  341. **
  342. **************************************************************************
  343. */
  344. int WriteGlobalColorTable(FILE * GIFfile /*pointer to GIF file*/)
  345. {
  346.    int i;
  347.  
  348.    /*write the color table
  349.  
  350.      NOTE: since this is a 256 grey scaled image the red, green, and blue
  351.        colors will all have the same intensity for each table entry.
  352.        This type of grey scale is put the table from intesities 0 to 255.
  353.    */
  354.    for(i = 0; i <= 255; i++) {
  355.       if(WriteGIFdata8(GIFfile, i))
  356.      return ERROR;
  357.       if(WriteGIFdata8(GIFfile, i))
  358.      return ERROR;
  359.       if(WriteGIFdata8(GIFfile, i))
  360.      return ERROR;
  361.    } /*end for*/
  362.    /*return the error code for no error if everything ran ok*/
  363.    return NO_ERROR;
  364. }
  365.  
  366.  
  367.  
  368. /*
  369. **************************************************************************
  370. **
  371. **     This function writes the image data portion of the
  372. **    GIF file.  If an error occured it returns ERROR otherwise NO_ERROR.
  373. **    It does this by calling the functions in this file that writes
  374. **    that data.
  375. **
  376. **************************************************************************
  377. */
  378. int WriteImage(    FILE * GIFfile,    /*pointer to GIF file*/
  379.         CHARH * ImageBuffer,
  380.                 /*pointer to the image buffer
  381.                   containing th RAW image*/
  382.         long Lines,    /*number of lines in image*/
  383.         long Samples     /*number of samples per line*/
  384.           )
  385. {
  386.  
  387.    /*Write the Image Descriptor block and return the appropriate error code
  388.      if there was an error*/
  389.    if(WriteImageDescriptor(GIFfile, Lines, Samples))
  390.       return ERROR;
  391.  
  392.    /*Write the Image Data block and return the appropriate error code
  393.      if there was an error*/
  394.    if(WriteImageDataBlock(GIFfile, ImageBuffer, Lines, Samples))
  395.       return ERROR;
  396.  
  397.    /*return the error code for no error if everything ran ok*/
  398.    return NO_ERROR;
  399. }
  400.  
  401.  
  402.  
  403.  
  404. /*
  405. ***************************************************************************
  406. **
  407. **     This function writes the image descriptor portion of the
  408. **    GIF image.  If an error occured it returns ERROR otherwise NO_ERROR.
  409. **
  410. ***************************************************************************
  411. */
  412. int WriteImageDescriptor(    FILE *         GIFfile, /*pointer to GIF file*/
  413.                 long        Lines,   /*number of lines
  414.                                                                 in image*/
  415.                 long        Samples  /*number of samples
  416.                                                                 per line*/
  417.             )
  418. {
  419.    /*write the image separator and return the
  420.      appropriate error code if there is an error*/
  421.    if(WriteGIFdata8(GIFfile, IMAGE_SEPARATOR))
  422.       return ERROR;
  423.  
  424.    /*write the image left position and return the
  425.      appropriate error code if there is an error*/
  426.    if(WriteGIFdata16(GIFfile, IMAGE_LEFT_POSITION))
  427.       return ERROR;
  428.  
  429.    /*write the image top position and return the
  430.      appropriate error code if there is an error*/
  431.    if(WriteGIFdata16(GIFfile, IMAGE_TOP_POSITION))
  432.       return ERROR;
  433.  
  434.    /*write the image width and return the
  435.      appropriate error code if there is an error*/
  436.    if(WriteGIFdata16(GIFfile, Samples))
  437.       return ERROR;
  438.  
  439.    /*write the image height and return the
  440.      appropriate error code if there is an error*/
  441.    if(WriteGIFdata16(GIFfile, Lines))
  442.       return ERROR;
  443.  
  444.    /*write the packed bit fields for:
  445.  
  446.      Local Color Table Flag     (bit  7  ),
  447.       Interlaced    Flag        (bit  6  ),
  448.      Sort Flag             (bit  5  ),
  449.      Reserved             (bits 4-3), and
  450.      Size of Local Color Table  (bits 2-0).
  451.  
  452.      Return the appropriate error code if there is an error
  453.    */
  454.    if(WriteGIFdata8(GIFfile, IMAGE_DESCRIPTOR_PACKED_BIT_FIELDS))
  455.         return ERROR;
  456.  
  457.    /*return the error code for no error if everything ran ok*/
  458.    return NO_ERROR;
  459. }
  460.  
  461.  
  462.  
  463. /*
  464. **************************************************************************
  465. **
  466. **     This function writes the image data block portion of the
  467. **    GIF image.  If an error occured it returns ERROR otherwise NO_ERROR.
  468. **    This function does the LZW compression of the image data and
  469. **    then writes it to the GIF file.  It should be noted that a simple
  470. **    hashing function is used to index into the LZW string table in
  471. **      order to speed the compression process.  It uses linear probing
  472. **    to find an item if a collision occures.
  473. **
  474. **    NOTE: This file uses CompuServe terminology and standard LZW
  475. **          terminology when ever possible.  The term string is used
  476. **          here because of this.  It should be noted that this is
  477. **          NOT an ascii string but rather raw data from the ImageBuffer.
  478. **          In order to fully understand how this code works it is recommended
  479. **          that one reads the CompuServe GIF specs before deciphering this
  480. **          code.
  481. **
  482. **************************************************************************
  483. */
  484. int WriteImageDataBlock(        FILE *         GIFfile,/*pointer to GIF file*/
  485.                 CHARH *        ImageBuffer,
  486.                             /*pointer to the
  487.                             ImageBuffer holding
  488.                             the raw image*/
  489.                 long        Lines,  /*number of lines*/
  490.                 long        Samples /*number of samples
  491.                             per line*/
  492.                         )
  493. {
  494.    StringTabNode *    HashTable    = (StringTabNode *)malloc(sizeof(StringTabNode   [TABLE_SIZE+OVERFLOW]));
  495.                               /*The Hash Table*/
  496.    CHARH **           HTString    = (unsigned char**)malloc(sizeof(unsigned char * [TABLE_SIZE+OVERFLOW]));
  497.                               /*The Hash Table's string
  498.                             pointers*/
  499.    unsigned char     GIFBuffer[BUFFER_SIZE];       /*a buffer to hold GIF
  500.                             image data before
  501.                             writing it*/
  502.    CHARH *        StartString     = ImageBuffer;/*a pointer to iterate
  503.                             thru the raw data*/
  504.    long         StringSize     = 1;           /*used to index off Start
  505.                             String*/
  506.    int             StringCode     = FIRST_NEW_OUTPUT_CODE;
  507.                               /*codes to put in string
  508.                             table*/
  509.    int             ByteCount    = 0;          /*holds the current
  510.                             location in the
  511.                             GIFBuffer*/
  512.    int             LastPos        = 0;             /*holds the location
  513.                             of the bit where to
  514.                             write the next byte
  515.                             in GIFBuffer*/
  516.    char         LeftOver        = 0;          /*holds the left over
  517.                             data that needs to be
  518.                             put in GIFBuffer*/
  519.    int             CodeBitSize     = START_CODE_BIT_SIZE;
  520.                               /*Holds the current bit
  521.                             size of the StringCode
  522.                             (for GIFs this is
  523.                             variable length)*/
  524.    int             CurrentCode;               /*Holds the currents
  525.                             string code pulled out
  526.                             of the HashTable*/
  527.    int             PreviousCode;               /*Holds the previous
  528.                             string code pulled
  529.                             out of the HashTable*/
  530.    int             i;                   /*an iterater to go thru
  531.                                                                     loops*/
  532.    long            ImageIndex    = 0;          /*used to index through image*/
  533.  
  534.  
  535.    /*check to see is dynamically allocated memory was allocated or not*/
  536.    if(HashTable == NULL) {
  537.       printf("Out of memory(HT)\n");
  538.       return ERROR;
  539.    }
  540.  
  541.    /*check to see is dynamically allocated memory was allocated or not*/
  542.    if(HTString == NULL) {
  543.       printf("Out of memory(HTS)\n");
  544.       return ERROR;
  545.    }
  546.  
  547.    /*write the minimum code size and return the
  548.      appropriate error code if there is an error*/
  549.    if(WriteGIFdata8(GIFfile, MIN_CODE_SIZE))
  550.       return ERROR;
  551.  
  552.    /*write the clear code to GIF file and return the
  553.      appropriate error code if there is an error*/
  554.    if(WriteToGIF(GIFfile, GIFBuffer, CLEAR_CODE, &LeftOver, &LastPos,
  555.               CodeBitSize, &ByteCount))
  556.       return ERROR;
  557.  
  558.    /*initialize the HashTable*/
  559.    InitTable(HashTable);
  560.  
  561. /*This is the main loop that goes thru the raw data in the ImageBuffer
  562.   and compresses it*/
  563.  
  564.   /*loop from the begining address of ImageBuffer to the ending address*/
  565.   while(ImageIndex < Lines*Samples){
  566.  
  567.      /*Pull the current code out of the Hash Table according to the
  568.        current string*/
  569.      CurrentCode = FindInTable(StartString, StringSize, HashTable, HTString);
  570.  
  571.      /*checks to see if the current code was in the hash table*/
  572.      if(CurrentCode == -1){
  573.  
  574.     /*write the PreviousCode to GIF file and return the appropriate
  575.       error code if there was an error*/
  576.     if(WriteToGIF(GIFfile, GIFBuffer, PreviousCode, &LeftOver, &LastPos,
  577.             CodeBitSize, &ByteCount))
  578.        return ERROR;
  579.  
  580.     /*increase the bit size for the string code if it outgrows the
  581.       old size*/
  582.     if(StringCode >= (1 << CodeBitSize))
  583.        CodeBitSize++;
  584.  
  585.     /*put the newest string in the table and its string code*/
  586.     PutInTable(StartString, StringSize, StringCode, HashTable, HTString);
  587.  
  588.     /*update string code and look at a new string*/
  589.     StringCode++;
  590.     StartString += (StringSize -1) * sizeof(unsigned char);
  591.     StringSize = 0;
  592.     ImageIndex--;
  593.      } /*end if*/
  594.  
  595.      /*remember CurrentCode for next time thru loop*/
  596.      PreviousCode = CurrentCode;
  597.  
  598.      /*increase string size for next time thru loop*/
  599.      StringSize++;
  600.  
  601.      /*increase index into image*/
  602.      ImageIndex++;
  603.  
  604.      /*this checks to see if the StringCode larger than its max size.
  605.        If so it writes the clear code to the GIF and resets everything*/
  606.      if(StringCode > MAX_STRING_CODE){
  607.  
  608.     /*write the clear code to GIF file and return the
  609.       appropriate error code if there is an error*/
  610.     if(WriteToGIF(GIFfile, GIFBuffer, CLEAR_CODE, &LeftOver,
  611.               &LastPos, CodeBitSize - 1, &ByteCount))
  612.        return ERROR;
  613.  
  614.     /*reset everything to initial values*/
  615.     StringSize     = 1;
  616.     StringCode     = FIRST_NEW_OUTPUT_CODE;
  617.     CodeBitSize   = START_CODE_BIT_SIZE;
  618.     InitTable(HashTable);
  619.      } /*end if*/
  620.  
  621.   } /*end while*/
  622.  
  623.   /*write the last string code found to GIF file and return the
  624.     appropriate error code if there is an error*/
  625.   if(WriteToGIF(GIFfile, GIFBuffer, CurrentCode, &LeftOver, &LastPos,
  626.         CodeBitSize, &ByteCount))
  627.      return ERROR;
  628.  
  629.   /*write the code to terminate image data to GIF file and return the
  630.     appropriate error code if there is an error*/
  631.   if(WriteToGIF(GIFfile, GIFBuffer, LZW_TERMINATOR_CODE, &LeftOver, &LastPos,
  632.          CodeBitSize, &ByteCount))
  633.      return ERROR;
  634.  
  635.   /*place the left over bits from compression in the GIF buffer*/
  636.   PutInGIFBuffer(GIFfile, GIFBuffer, LeftOver, &ByteCount);
  637.  
  638.   /*write the GIF buffer to GIF file if needed and return the
  639.     appropriate error code if there was an error*/
  640.   if(ByteCount) {
  641.      if(WriteGIFdata8(GIFfile, ByteCount))
  642.     return ERROR;
  643.      for(i = 0; i < ByteCount; i++)
  644.     if(WriteGIFdata8(GIFfile, GIFBuffer[i]))
  645.        return ERROR;
  646.   } /*end if*/
  647.  
  648.   /*write the BLOCK_TERMINATOR and return the
  649.     appropriate error code if there is an error*/
  650.   if(WriteGIFdata8(GIFfile, BLOCK_TERMINATOR))
  651.      return ERROR;
  652.  
  653.   /*normal exit*/
  654.   return NO_ERROR;
  655. }
  656.  
  657.  
  658.  
  659.  
  660.  
  661. /*
  662. **************************************************************************
  663. **
  664. **    This is used to compare LZW strings(see WriteImageDataBlock). Instead
  665. **    of a regular C string terminator it uses size to indicate how long
  666. **    the strings is (similar to a pascal string) because a NULL is
  667. **    considered valid raw data.  This is used to determine if two
  668. **    strings or string segments are the same.  If they are then
  669. **    it returns TRUE, otherwise it returns FALSE.  The second
  670. **    string may contain a NULL pointer; if it does a FALSE is returned
  671. **    regardless.
  672. **
  673. **************************************************************************
  674. */
  675. BOOLEAN CompareString(    CHARH *         String1,/*first string*/
  676.             int             Size1,  /*size of first string*/
  677.             CHARH *             String2,/*second string*/
  678.             int             Size2   /*size of second
  679.                                                                     string*/
  680.              )
  681. {
  682.    int i;
  683.  
  684.    /*see if string sizes are differnt or a NULL is found. If so FALSE
  685.      is returned*/
  686.    if((Size1 != Size2) || (String2 == NULL))
  687.       return FALSE;
  688.  
  689.    /*compare the strings*/
  690.    for(i = 0; i < Size1; i++)
  691.       if(String1[i] != String2[i])
  692.      return FALSE;
  693.  
  694.    /*return here if strings are the same*/
  695.    return TRUE;
  696. }
  697.  
  698.  
  699.  
  700.  
  701. /*
  702. **************************************************************************
  703. **
  704. **    This puts a LZW string into the string table using a hashing
  705. **    function.
  706. **
  707. **************************************************************************
  708. */
  709. void PutInTable(    CHARH *         StringToPut,/*the string*/
  710.             int             StringSize, /*size of string*/
  711.             int             StringCode, /*code to represent
  712.                                   string in GIF*/
  713.             StringTabNode *     HashTable,  /*the hash table*/
  714.             CHARH **        HTString    /*Hash Table string
  715.                                   pointers to put
  716.                                   string in*/
  717.         )
  718. {
  719.    /*derive a location in the HashTable*/
  720.    long Location = (((long)StringToPut[0] + (long)StringToPut[1]) * (long)StringSize * 101) % TABLE_SIZE;
  721.  
  722.    /*see if a collision occured and find next blank spot*/
  723.    while(HashTable[Location].StringSize != 0)
  724.       Location ++;
  725.  
  726.    /*place string and its string code in HashTable*/
  727.    HTString[Location] = StringToPut;
  728.    HashTable[Location].StringSize = StringSize;
  729.    HashTable[Location].StringCode  = StringCode;
  730.  
  731.    return;
  732. }
  733.  
  734.  
  735.  
  736.  
  737. /*
  738. **************************************************************************
  739. **
  740. **    This initializes the string table to contain nothing.
  741. **
  742. **************************************************************************
  743. */
  744. void InitTable(StringTabNode HashTable[TABLE_SIZE+OVERFLOW] /*the hash table*/)
  745. {
  746.    long i;
  747.  
  748.    /*initialize the HashTable to zero length strings*/
  749.    for(i = 0; i < TABLE_SIZE + OVERFLOW; i++)
  750.       HashTable[i].StringSize = 0;
  751.  
  752.    return;
  753. }
  754.  
  755.  
  756.  
  757. /*
  758. **************************************************************************
  759. **
  760. **    This puts GIF variable length codes into a buffer.   If the
  761. **    buffer gets full it writes it to the GIF file and clears the
  762. **    buffer.
  763. **
  764. **************************************************************************
  765. */
  766. int PutInGIFBuffer(    FILE *         GIFfile,   /*pointer to GIF file*/
  767.             unsigned char * GIFBuffer, /*pointer to GIF buffer*/
  768.             unsigned char     ByteToPut, /*the byte to put in buffer*/
  769.             int *         ByteCount  /*index into the buffer*/
  770.           )
  771. {
  772.    int i;
  773.  
  774.    /*put data into the GIF buffer*/
  775.    GIFBuffer[(* ByteCount)++] = ByteToPut;
  776.  
  777.    /*see if the buffer is full.  if so write it to GIF file*/
  778.    if((* ByteCount) > BUFFER_SIZE - 1) {
  779.  
  780.       /*put buffer size at the top of image data sub-block*/
  781.       if(WriteGIFdata8(GIFfile, BUFFER_SIZE))
  782.      return ERROR;
  783.  
  784.       /*write data to GIF file*/
  785.       for(i = 0; i < BUFFER_SIZE; i++)
  786.      if(WriteGIFdata8(GIFfile, GIFBuffer[i]))
  787.         return ERROR;
  788.  
  789.       /*reset the byte count*/
  790.       (* ByteCount) = 0;
  791.    } /*end if*/
  792.    return NO_ERROR;
  793. }
  794.  
  795.  
  796.  
  797.  
  798. /*
  799. **************************************************************************
  800. **
  801. **    This finds a string in the string table using a hashing function
  802. **    and returns its variable length code as its value. If nothing is
  803. **    found then NULL is returned
  804. **
  805. **    NOTE: the variable length code is returned as an int. The unused
  806. **          bits are set to 0.
  807. **
  808. **************************************************************************
  809. */
  810. int FindInTable(    CHARH *         StringToFind, /*the string*/
  811.             int             StringSize,   /*size of string*/
  812.             StringTabNode *     HashTable,    /*the table to
  813.                                 look in*/
  814.             CHARH **        HTString      /*Hash Table
  815.                                 Strings to look
  816.                                 through*/
  817.         )
  818. {
  819.    long Location = 0;
  820.  
  821.    /*if string size is one its location is the value of the single string byte*/
  822.    if(StringSize == 1)
  823.       return (int)StringToFind[0];
  824.  
  825.    /*find string in HashTable*/
  826.    for(Location = (((long)StringToFind[0] + (long)StringToFind[1]) * (long)StringSize * 101) % TABLE_SIZE;
  827.        Location < TABLE_SIZE + OVERFLOW;
  828.        Location++  )
  829.  
  830.       /*if a StringSize 0 is found then it is not in the table*/
  831.       if(HashTable[Location].StringSize == 0)
  832.      return (-1);
  833.  
  834.       /*if the string is found return its StringCode*/
  835.       else if(CompareString(StringToFind, StringSize,
  836.                 HTString[Location],
  837.                 HashTable[Location].StringSize))
  838.           return HashTable[Location].StringCode;
  839.  
  840.    /*went thru the entire string table and nothing was found*/
  841.    return (-1);
  842. }
  843.  
  844.  
  845.  
  846.  
  847. /*
  848. **************************************************************************
  849. **
  850. **    This determines the size of the variable length code and packs
  851. **    it into bytes.  It takes those bytes and puts them in the GIF
  852. **    buffer.  If the last part of the varible length code is
  853. **    not long enough to pack into a byte it is put into a left over
  854. **    variable to be packed into a byte next time through.
  855. **
  856. **************************************************************************
  857. */
  858. int WriteToGIF(        FILE *         GIFfile,     /*pointer to GIF file*/
  859.             unsigned char * GIFBuffer,   /*pointer to GIF buffer*/
  860.             int         NewData,     /*data to write to GIF*/
  861.             char *         LeftOver,    /*left over bits to be
  862.                                packed next time around*/
  863.             int *         LastPos,     /*the bit position of the
  864.                                last bit used*/
  865.             int         CodeBitSize, /*that size of the data to
  866.                                be written*/
  867.             int *         ByteCount    /*index into the GIF
  868.                                buffer*/
  869.  
  870.           )
  871. {
  872.    /*pack LeftOver with the NewData*/
  873.    unsigned long CodeToWrite = (unsigned long)((unsigned long)NewData *(1 << (unsigned long)(*LastPos)))|(unsigned long)(*LeftOver);
  874.  
  875.    /*write the first byte of the packed string tokens for this round and
  876.      return the appropriate error code if there is an error*/
  877.    if(PutInGIFBuffer(GIFfile, GIFBuffer, CodeToWrite & 255, ByteCount))
  878.       return ERROR;
  879.  
  880.    /*see if only one byte had to be written to GIFBuffer*/
  881.    if((* LastPos) + CodeBitSize < 16)
  882.       /*set up LeftOver for next time thru*/
  883.       (* LeftOver) = CodeToWrite >> 8;
  884.  
  885.    else {
  886.  
  887.       /*write the second byte of the packed string tokens for this round and
  888.     return the appropriate error code if there is an error*/
  889.       if(PutInGIFBuffer(GIFfile, GIFBuffer,(CodeToWrite & 65280)/256,ByteCount))
  890.      return ERROR;
  891.  
  892.       /*set up LeftOver for next time thru*/
  893.       (* LeftOver) = CodeToWrite >> 16;
  894.    } /*end if*/
  895.  
  896.    /*set up a new position for next time thru*/
  897.    (* LastPos) = ((* LastPos) + CodeBitSize) % 8;
  898.    return NO_ERROR;
  899. }
  900.  
  901.  
  902.  
  903.  
  904.  
  905.  
  906.  
  907. /*
  908. *****************************************************************************
  909. **
  910. **    This writes 8 bit data to the GIF file.
  911. **
  912. ****************************************************************************
  913. */
  914. int WriteGIFdata8(    FILE *        GIFfile, /*pointer to GIF file*/
  915.             unsigned char   GIFdata  /*8 bit data to write*/
  916.           )
  917. {
  918.    /*write 8 bit data*/
  919.    fwrite((unsigned char *)&GIFdata, sizeof(unsigned char), 1, GIFfile);
  920.  
  921.    if(ferror(GIFfile))
  922.       /*exit with an error*/
  923.       return ERROR;
  924.  
  925.    /*exit normally*/
  926.    return NO_ERROR;
  927. }
  928.  
  929.  
  930. /*
  931. *******************************************************************************
  932. **
  933. **    This writes 16 bit data to the GIF file.  It is in the form
  934. **    lo-byte hi-byte.  It call WriteGIFdata8 to write those bytes
  935. **    to the GIF file.
  936. **
  937. ******************************************************************************
  938. */
  939. int WriteGIFdata16(    FILE *        GIFfile, /*pointer to GIF file*/
  940.             unsigned int    GIFdata  /*16 bit data to write*/
  941.            )
  942. {
  943.  
  944.    /*break up 16 bit value into lo byte and hi byte*/
  945.    if (WriteGIFdata8(GIFfile, LO_BYTE_16BIT))
  946.       /*exit with an error*/
  947.       return ERROR;
  948.    else
  949.       if (WriteGIFdata8(GIFfile, HI_BYTE_16BIT))
  950.      /*exit with an error*/
  951.      return ERROR;
  952.       else
  953.      /*exit normally*/
  954.      return NO_ERROR;
  955. }
  956.  
  957.  
  958.  
  959.